MFA認証を使ったAssumeRoleでシンプルにTerraformを実行する(aws configure export-credentials)
Terraform実行時のMFA認証を使ったAssume Roleを楽にできる方法がないか調べていたら、以下のコメントを見つけました。
Doesn't ask MFA token code when using assume_role with MFA required #2420
どうやらツールや長いコマンドの実行なしで、MFA認証ありでも簡単にAssume Roleができそうです。
便利だったのでブログにしてみました。
TerraformのMFA認証事情は以下のブログをご確認ください。
結論
この方法では、aws-vaultやaws-mfaなどのツールは不要です。
以下のようにProfileを用意して、terraformのコマンドを打つだけです。
[profile myprofile] output=json region=ap-northeast-1 role_arn=arn:aws:iam::01234567890:role/sato.masaki mfa_serial=arn:aws:iam::12345678901:mfa/sato.masaki [profile myprofile-tf] credential_process = aws configure export-credentials --profile myprofile
provider "aws" { region = "ap-northeast-1" profile = "myprofile-tf" # tfファイル側で記載せずに、環境変数AWS_PROFILEで渡してもOK }
aws configure export-credentials
上記の./aws/config
内のaws configure export-credentials
あまり見慣れない方も多いのではないでしょうか。(私自身も使ったことがありませんでした)
credential_process
は認証情報を取得するためのコマンドを指定するオプションです。例えばaws-vaultのような外部ツールで取得した認証情報を渡したりできます。
[profile common] credential_process=aws-vault --prompt terminal export classmethod --duration 12h --format=json
上記は、AWS Vaultで端末内のAWSアクセスキー平文保存をやめてみた | DevelopersIOから引用。
aws configure export-credentials
は既存のprofileから認証情報を取得し、出力するコマンドです。
(デフォルトは、credential_process
で予期されるスキーマで出力されます。)
$ aws configure export-credentials --profile "myprofile" { "Version": 1, "AccessKeyId": "<アクセスキーID>", "SecretAccessKey": "<シークレットアクセスキー>", "SessionToken": "<セッショントークン>", "Expiration": "2024-04-18T03:31:52+00:00" }
profilemyprofile
から認証情報を取得して、profilemyprofile-tf
に認証情報をセットしています。
- 外部プロセスを使用して認証情報を作成する - AWS Command Line Interface
- export-credentials — AWS CLI 2.15.39 Command Reference
やってみた
Assume Roleして、Terraformでリソースを作成してみます。
AWSCLI Profileの準備
IAMユーザー管理アカウント(スイッチ元アカウント)でIAMアクセスキーを発行して、AWS CLIにアクセスキーを設定します。(既に実施済みの場合は、不要)
$ aws configure AWS Access Key ID [None]: AWS Secret Access Key [None]: Default region name [ap-northeast-1]: Default output format :
.aws/config
に以下のように記述を追加します。
ARNやリージョン等は適宜置き換えてください。
[profile default] output=json region=ap-northeast-1 [profile sandbox] output=json region=ap-northeast-1 role_arn=arn:aws:iam::1234567890:role/test.taro # Terraformデプロイ先アカウントのIAMロール(要置き換え) mfa_serial=arn:aws:iam::2345678901:mfa/test.taro # IAMユーザーのMFAの識別子(要置き換え) source_profile=default [profile sandbox-tf] credential_process = aws configure export-credentials --profile "sandbox"
設定したprofileを使って、AWS CLIを実行してみます。
コマンド実行時にMFA Codeが求められます。入力して、以下のように出力が得られたらOKです。
$ aws sts get-caller-identity --profile sandbox-tf Enter MFA code for arn:aws:iam::2345678901:mfa/test.taro: { "UserId": "AROAS52FR6JWMTMPR7PHT:botocore-session-1713404114", "Account": "1234567890", "Arn": "arn:aws:sts::1234567890:assumed-role/test.taro/botocore-session-1713404114" }
Terraformの実行
以下のコードを用意して、terraform init
やterraform [plan/apply]
を試していきます。
今回はコード中でprofileを指定していますが、コード中で指定せずに環境変数AWS_PROFILE
で指定しても問題ありません。
(export AWS_PROFILE="sandbox-tf"
)
terraform { backend "s3" { bucket = "<State管理バケット名>" key = "profile-test/terraform.state" region = "ap-northeast-1" profile = "sandbox-tf" } } provider "aws" { region = "ap-northeast-1" profile = "sandbox-tf" } resource "aws_vpc" "my_vpc" { cidr_block = "10.0.0.0/16" tags = { Name = "my-vpc" } }
Terraform CLIを試してみます。それぞれ正常に動作します。
セッションが切れていたら、コマンド実行時にMFA Codeが求められます。
$ terraform init # 省略 Terraform has been successfully initialized! # 省略 $ terraform plan # 省略 Plan: 1 to add, 0 to change, 0 to destroy. # 省略 $ terraform apply # 省略 Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
おまけ: 通常のスイッチロール用Profileでやってみる(失敗)
credential_process
を使わないProfileで実行 したケースを、おまけとして書いておきます。
今回の環境では、sandbox
が通常のProfileになります。
[profile sandbox] output=json region=ap-northeast-1 role_arn=arn:aws:iam::1234567890:role/test.taro # Terraformデプロイ先アカウントのIAMロール(要置き換え) mfa_serial=arn:aws:iam::2345678901:mfa/test.taro # IAMユーザーのMFAの識別子(要置き換え) source_profile=default
terraform { backend "s3" { bucket = "<State管理バケット名>" key = "profile-test/terraform.state" region = "ap-northeast-1" profile = "sandbox" } } provider "aws" { region = "ap-northeast-1" profile = "sandbox" } resource "aws_vpc" "my_vpc" { cidr_block = "10.0.0.0/16" tags = { Name = "my-vpc" } }
Terraform CLIを実行してみます。以下のエラーメッセージが出力されます。
TerraformはMFAトークンを要求しないので、エラーになってしまいます。
$ terraform init Initializing the backend... ╷ │ Error: assume role with MFA enabled, but AssumeRoleTokenProvider session option not set. │ │ ╵ $ terraform plan # backendのprofileを変更してinitを成功させた後 Planning failed. Terraform encountered an error while generating this plan. ╷ │ Error: assume role with MFA enabled, but AssumeRoleTokenProvider session option not set. │ │ with provider["registry.terraform.io/hashicorp/aws"], │ on main.tf line 10, in provider "aws": │ 10: provider "aws" { │
おわりに
私は普段aws sts assume-role
の結果(AWSアクセスキーID、シークレットキー、セッショントークン)を環境変数に設定するスクリプトを使って、Terraformを実行していました。
しかし、今回のサンプルコードのようにProviderの部分でprofileを指定されていると、この方法は少し面倒です。
.aws/config
にprofileの設定と、.aws/credentials
に都度認証情報をいれる必要もあります。(他にも色々方法ありそうですが、いい方法が思いつかない)
今回紹介した方法は、tfファイル上でprofile指定がある場合でも使えますし、セットアップも容易なので今後は使っていきたいと思います。
以上、AWS事業本部の佐藤(@chari7311)でした。